﻿using maranov.SymlinkManager.ApplicationPrivilege;
using System;
using System.Collections.Generic;
using System.IO;

namespace maranov.SymlinkManager.FilesystemLinks.PrivilegeCheckProviders
{
    /// <summary>
    /// Privilege checks provider for the symbolic link creation.
    /// </summary>
    public class SymbolicLinkPrivilegeCheckProvider : IPrivilegeCheckProvider
    {
        public IEnumerable<PrivilegeCheck> PrivilegeCheckRoutines
        {
            get
            {
                return new List<PrivilegeCheck>() 
                { 
                    TempFolderSymlinkCreationCheck
                };
            }
        }

        /// <summary>
        /// Checks the required process privileges by attempting symlink creation in the temporary folder.
        /// </summary>
        private static readonly PrivilegeCheck TempFolderSymlinkCreationCheck =
            new PrivilegeCheck(
                delegate
                {
                    // Symlink target
                    string testFile =
                        System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + "_original";
                    // Symlink
                    string testLink =
                        System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + "_link";

                    ISymbolicLink link = new SymbolicLink(testLink, testFile);
                    try
                    {
                        // Create a file.
                        File.Open(testFile, FileMode.OpenOrCreate).Close();

                        // Create a symlink.
                        if (link.Exists)
                            link.Remove();  // Remove if it exists.
                        link.Create();

                        // Check the symlink.
                        File.Open(testLink, FileMode.Open).Close();

                        return true;
                    }
                    catch
                    {
                        return false;
                    }
                    finally
                    {
                        try
                        {
                            File.Delete(testFile);
                        }
                        catch { }
                        if (link.Exists)
                        {
                            try
                            {
                                link.Remove(true);
                            }
                            catch { }
                        }
                    }
                }
                );
    }
}
